package references

import (
	"hi-jvm/instructions/base"
	"hi-jvm/rtda"
	"hi-jvm/rtda/heap"
)

/*
给一个静态变量赋值
需要两个操作数
1. unint16位索引， 从当前类的运行时常量池中找到一个字段符号引用，解析这个符号引用，就可以知道给哪个静态变量赋值
2. 值： 从操作数栈中弹
*/
// Set static field in class
type PUT_STATIC struct{ base.Index16Instruction }

/*

 */
func (self *PUT_STATIC) Execute(frame *rtda.Frame) {
	field, class := readStaticClassInfo(self.Index, frame, true)

	slots := class.StaticVars

	if field.IsInt32() {
		slots.SetInt(field.SlotId, frame.OperandStack.PopInt())
		return
	}

	if field.IsFloat() {
		slots.SetFloat(field.SlotId, frame.OperandStack.PopFloat())
		return
	}

	if field.IsInt64() {
		slots.SetLong(field.SlotId, frame.OperandStack.PopLong())
		return
	}

	if field.IsDouble() {
		slots.SetDouble(field.SlotId, frame.OperandStack.PopDouble())
		return
	}

	if field.IsRef() {
		slots.SetRef(field.SlotId, frame.OperandStack.PopRef())
		return
	}
}

func readStaticClassInfo(index uint, frame *rtda.Frame, istatic bool) (field *heap.Field, class *heap.Class) {
	currentMethod := frame.Method
	currentClass := currentMethod.Class
	cp := currentClass.ConstantPool
	fieldRef := cp.GetConstant(index).(*heap.FieldRef)
	field = fieldRef.ResolvedField()
	class = field.Class
	// todo: init class

	if !class.InitClassIfNotInited(frame) {
		return
	}

	if istatic && !field.IsStatic() {
		panic("java.lang.IncompatibleClassChangeError")
	}

	if !istatic && field.IsStatic() {
		panic("java.lang.IncompatibleClassChangeError")
	}
	if field.IsFinal() {
		if currentClass != class || currentMethod.Name != "<clinit>" {
			panic("java.lang.IllegalAccessError")
		}
	}
	return
}
